#include "parse.h"

// easy parse
std::vector<variable> parse(std::vector<token> tokens, std::string input) {
    parser psr(tokens, input);
    psr.parse();
    return psr.get_variables();
}

// variable
variable::variable(std::string name, tokentype type, std::string strvalue) : name(name), type(type), strvalue(strvalue), intvalue(0) {}
variable::variable(std::string name, tokentype type, int intvalue) : name(name), type(type), strvalue(""), intvalue(intvalue) {}
variable::variable(const variable &v) : name(v.name), type(v.type), strvalue(v.strvalue), intvalue(v.intvalue) {}

std::string variable::get_str_value() {
    return strvalue;
}
int variable::get_int_value() {
    return intvalue;
}
std::string variable::to_string() {
    std::stringstream bufstream;
    std::string type;
    if (this->type == tokentype::WORD) {
        type = "WORD";
    } else if (this->type == tokentype::LETTER) {
        type = "LETTER";
    } else if (this->type == tokentype::DIGIT) {
        type = "DIGIT";
    } else if (this->type == tokentype::NUMBER) {
        type = "NUMBER";
    } else if (this->type == tokentype::X) {
        type = "X";
    } else if (this->type == tokentype::CONST) {
        type = "CONST";
    }
    bufstream << name << " \t " << type << " \t " << strvalue << " \t " << intvalue;
    return bufstream.str();
}

// parser
parser::parser(std::vector<token> tokens, std::string input) : tokens(tokens), input(input), current(0) {}

void parser::parse() {
    for (auto tk : tokens) {
        parse_token(tk);
    }
    if (!isEnd()) {
        throw std::string("input name does not match pattern [") + residu() + "]";
    }
}
std::vector<variable> parser::get_variables() {
    return variables;
}

std::string parser::to_string() {
    std::stringstream bufstream;
    bufstream << input << '\n';
    for (auto tk : tokens) {
        bufstream << tk.to_string() << '\n';
    }
    for (auto var : variables) {
        bufstream << var.to_string() << '\n';
    }
    return bufstream.str();
}
void parser::parse_token(token tk) {
    switch (tk.type) {
    case tokentype::WORD:
        parse_word(tk);
        break;
    case tokentype::LETTER:
        parse_letter(tk);
        break;
    case tokentype::DIGIT:
        parse_digit(tk);
        break;
    case tokentype::NUMBER:
        parse_number(tk);
        break;
    case tokentype::X:
        parse_x(tk);
        break;
    case tokentype::CONST:
        parse_const(tk);
        break;
    }
}

char parser::advance() {
    current++;
    return input[current - 1];
}
std::string parser::residu() { // 匹配失败后输出后续所有未匹配的字串
    std::string ret;
    while (!isEnd()) {
        ret += advance();
    }
    return ret;
}
char parser::peek() {
    if (isEnd()) {
        return '\0';
    }
    return input[current];
}
bool parser::isEnd() {
    return current >= input.length();
}
void parser::parse_letter(token tk) {
    char c = peek();
    if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
        throw std::string("input name does not match pattern [") + residu() + "]";
    }
    std::string strvalue = "";
    for (int i = 0; i < tk.count && c != '\0'; ++i) {
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            strvalue += advance();
            c = peek();
        } else {
            throw std::string("input name does not match pattern [") + residu() + "]";
        }
    }
    variables.push_back(variable(tk.varname, tokentype::LETTER, strvalue));
}
void parser::parse_word(token tk) {
    char c = peek();
    if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
        throw std::string("input name does not match pattern [") + residu() + "]";
    }
    std::string strvalue = "";
    while (c != '\0' && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
        strvalue += advance();
        c = peek();
    }
    variables.push_back(variable(tk.varname, tokentype::WORD, strvalue));
}
void parser::parse_digit(token tk) {
    char c = peek();
    if (!((c >= '0' && c <= '9') || (c == '-'))) {
        throw std::string("input name does not match pattern [") + residu() + "]";
    }
    std::string strvalue = "";
    int intvalue;
    for (int i = 0; i < tk.count && c != '\0'; ++i) {
        if (c >= '0' && c <= '9') {
            strvalue += advance();
            c = peek();
        } else {
            throw std::string("input name does not match pattern [") + residu() + "]";
        }
    }
    std::stringstream bufstream(strvalue);
    bufstream >> intvalue;
    variables.push_back(variable(tk.varname, tokentype::DIGIT, intvalue));
}
void parser::parse_number(token tk) {
    char c = peek();
    if (!((c >= '0' && c <= '9') || (c == '-'))) {
        throw std::string("input name does not match pattern [") + residu() + "]";
    }
    std::string strvalue = "";
    int intvalue;
    while (c != '\0' && (c >= '0' && c <= '9')) {
        strvalue += advance();
        c = peek();
    }
    std::stringstream bufstream(strvalue);
    bufstream >> intvalue;
    variables.push_back(variable(tk.varname, tokentype::NUMBER, intvalue));
}
void parser::parse_x(token tk) {
    char c = peek();
    std::string strvalue = "";
    for (int i = 0; i < tk.count && c != '\0'; ++i) {
        strvalue += advance();
        c = peek();
    }
    variables.push_back(variable(tk.varname, tokentype::X, strvalue));
}
void parser::parse_const(token tk) {
    char c = peek();
    for (auto vc : tk.varname) {
        if (c == vc) {
            advance();
            c = peek();
        } else {
            throw std::string("input name does not match pattern [") + residu() + "]";
        }
    }
}
